/// <reference types="node" />
import { join } from 'path';
import * as fs from 'fs';
import * as crypto from 'crypto';

/**
 * 编辑器选项接口
 */
interface EditorOptions {
    Editor: {
        Dialog: any;
        Project: {
            path: string;
        };
    };
}

/**
 * 对话框结果接口
 */
interface DialogResult {
    canceled: boolean;
    filePaths: string[];
    value?: string;
}

/**
 * Manifest文件接口
 */
interface VersionManifest {
    packageUrl: string;
    remoteManifestUrl: string;
    remoteVersionUrl: string;
    version: string;
}

/**
 * 项目Manifest文件接口
 */
interface ProjectManifest extends VersionManifest {
    assets: Record<string, { md5: string, size: number }>;
    searchPaths: string[];
}

/**
 * 热更新工具主类
 */
export class HotUpdateTools {
    /**
     * 生成manifest文件
     * @param options 编辑器传入的选项
     */
    public generateManifest(options: EditorOptions) {
        const Editor = options.Editor;
        
        // 显示配置对话框
        Editor.Dialog.select({
            title: '生成Manifest文件',
            path: Editor.Project.path,
            type: 'directory',
            multi: false,
            button: '选择输出目录'
        }).then((result: DialogResult) => {
            if (result.canceled || !result.filePaths.length) {
                Editor.Dialog.warn('未选择输出目录，操作已取消');
                return;
            }

            const outputDir = result.filePaths[0];
            
            // 显示版本输入对话框
            Editor.Dialog.input({
                title: '输入版本号',
                placeholder: '例如: 1.0.0',
                value: '1.0.0',
                confirmText: '确认',
                cancelText: '取消'
            }).then((inputResult: DialogResult) => {
                if (inputResult.canceled || !inputResult.value) {
                    Editor.Dialog.warn('未输入版本号，操作已取消');
                    return;
                }

                const version = inputResult.value;
                
                // 显示服务器URL输入对话框
                Editor.Dialog.input({
                    title: '输入热更新服务器URL',
                    placeholder: '例如: http://localhost/hotupdate/',
                    value: 'http://localhost/hotupdate/',
                    confirmText: '确认',
                    cancelText: '取消'
                }).then((urlResult: DialogResult) => {
                    if (urlResult.canceled || !urlResult.value) {
                        Editor.Dialog.warn('未输入服务器URL，操作已取消');
                        return;
                    }

                    const serverUrl = urlResult.value.endsWith('/') ? urlResult.value : urlResult.value + '/';
                    
                    // 显示资源目录选择对话框
                    Editor.Dialog.select({
                        title: '选择需要热更新的资源目录',
                        path: join(Editor.Project.path, 'assets'),
                        type: 'directory',
                        multi: true,
                        button: '选择资源目录'
                    }).then((dirsResult: DialogResult) => {
                        if (dirsResult.canceled || !dirsResult.filePaths.length) {
                            Editor.Dialog.warn('未选择资源目录，将只生成基本manifest文件');
                            // 生成基本manifest文件
                            this.generateBasicManifests(outputDir, version, serverUrl);
                            return;
                        }

                        const assetDirs = dirsResult.filePaths;
                        // 生成包含资源的manifest文件
                        this.generateFullManifests(outputDir, version, serverUrl, assetDirs, Editor.Project.path);
                    });
                });
            });
        });
    }

    /**
     * 生成基本的manifest文件（不包含资源列表）
     * @returns 生成的manifest对象
     */
    private generateBasicManifests(outputDir: string, version: string, serverUrl: string): { versionManifest: VersionManifest, projectManifest: ProjectManifest } {
        // 创建version.manifest
        const versionManifest = {
            packageUrl: serverUrl,
            remoteManifestUrl: `${serverUrl}project.manifest`,
            remoteVersionUrl: `${serverUrl}version.manifest`,
            version: version
        };

        // 创建project.manifest
        const projectManifest = {
            ...versionManifest,
            assets: {},
            searchPaths: []
        };

        // 确保输出目录存在
        try {
            if (!fs.existsSync(outputDir)) {
                fs.mkdirSync(outputDir, { recursive: true });
            }

            // 写入文件
            fs.writeFileSync(
                join(outputDir, 'version.manifest'),
                JSON.stringify(versionManifest, null, 2)
            );
            
            fs.writeFileSync(
                join(outputDir, 'project.manifest'),
                JSON.stringify(projectManifest, null, 2)
            );

            console.log(`基本manifest文件已生成到: ${outputDir}`);
            return { versionManifest, projectManifest };
        } catch (error) {
            console.error(`生成manifest文件失败: ${error instanceof Error ? error.message : String(error)}`);
            throw error;
        }
    }

    /**
     * 生成完整的manifest文件（包含资源列表）
     */
    private generateFullManifests(outputDir: string, version: string, serverUrl: string, assetDirs: string[], projectPath: string) {
        // 先生成基本manifest
        const { projectManifest } = this.generateBasicManifests(outputDir, version, serverUrl);
        
        // 收集资源信息
        const assets: Record<string, { md5: string, size: number }> = {};
        
        // 处理每个资源目录
        for (const dir of assetDirs) {
            this.collectAssets(dir, assets, projectPath);
        }
        
        // 更新project.manifest中的assets
        projectManifest.assets = assets;
        
        // 写入更新后的project.manifest
        fs.writeFileSync(
            join(outputDir, 'project.manifest'),
            JSON.stringify(projectManifest, null, 2)
        );
        
        console.log(`完整manifest文件已生成到: ${outputDir}`);
        console.log(`共包含 ${Object.keys(assets).length} 个资源文件`);
    }

    /**
     * 递归收集目录中的资源文件
     */
    private collectAssets(dir: string, assets: Record<string, { md5: string, size: number }>, projectPath: string) {
        const files = fs.readdirSync(dir);
        
        for (const file of files) {
            const fullPath = join(dir, file);
            const stat = fs.statSync(fullPath);
            
            if (stat.isDirectory()) {
                // 递归处理子目录
                this.collectAssets(fullPath, assets, projectPath);
            } else {
                // 处理文件
                // 跳过一些不需要的文件类型
                if (file.endsWith('.meta') || file.endsWith('.DS_Store')) {
                    continue;
                }
                
                // 计算相对于项目根目录的路径
                let relativePath = fullPath.replace(projectPath, '').replace(/\\\\/g, '/');
                if (relativePath.startsWith('/')) {
                    relativePath = relativePath.substring(1);
                }
                
                // 计算MD5和文件大小
                const fileContent = fs.readFileSync(fullPath);
                const md5 = crypto.createHash('md5').update(fileContent).digest('hex');
                const size = stat.size;
                
                // 添加到资源列表
                assets[relativePath] = {
                    md5,
                    size
                };
            }
        }
    }
}

/**
 * 编辑器扩展入口
 */
export function load() {
    console.log('热更新工具已加载');
}

/**
 * 编辑器扩展卸载
 */
export function unload() {
    console.log('热更新工具已卸载');
}

/**
 * 导出方法供编辑器调用
 */
export const methods = {
    generateManifest(options: any) {
        const tools = new HotUpdateTools();
        tools.generateManifest(options);
    }
};